/**
 * @class   wosh::NetworkChannel
 * @brief   Interface of a generic communication channel between WOSH hosts.
 *
 *          Posting is usually asynchronous, message delivery is transient.
 *
 *
 * @see     wosh::NetworkProtocol
 * @see     wosh::NetworkManager
 ****************************************************************************
 * @version $Id: NetworkChannel.h 2836 2010-08-03 01:35:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR UserS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_NetworkChannel_H__
 #define __WOSH_Core_NetworkChannel_H__

 #include <woshDefs.h>
 #include <core/Object.h>
 #include <core/MessageQueue.h>
 #include <core/PropertiesProvider.h>
 #include <core/MethodsProvider.h>
 #include <core/Bus.h>
 #include <core/LogContext.h>
 #include <core/WoshHost.h>

 #include <vector>

namespace wosh {

 #define _NetworkChannel_KEY_AutoBind				"AutoBind"
 #define _NetworkChannel_KEY_BindAddress			"BindAddress"
 #define _NetworkChannel_KEY_ConnectAddress			"ConnectAddress"
 #define _NetworkChannel_KEY_Connected				"Connected"
 #define _NetworkChannel_KEY_Listening				"Listening"
 #define _NetworkChannel_KEY_Priority				"Priority"

 #define _NetworkChannel_KEY_MessageTxTs			"MessageTxTs"
 #define _NetworkChannel_KEY_MessageRxTs			"MessageRxTs"
 #define _NetworkChannel_KEY_MessageTxCount			"MessageTxCount"
 #define _NetworkChannel_KEY_MessageTxErrorCount	"MessageTxErrorCount"
 #define _NetworkChannel_KEY_MessageRxCount			"MessageRxCount"
 #define _NetworkChannel_KEY_MessageRxErrorCount	"MessageRxErrorCount"

 #define _NetworkChannel_KEY_DumpOutputTo			"DumpOutputTo"
 #define _NetworkChannel_KEY_DumpInputTo			"DumpInputTo"

 #define _NetworkChannel_METHOD_connect				"connect"
 #define _NetworkChannel_METHOD_disconnect			"disconnect"
 #define _NetworkChannel_METHOD_ping				"ping"

 #define _NetworkChannel_EVENT_ListChanged			"NetworkChannel_ListChanged"
 #define _NetworkChannel_EVENT_ConnectionChanged	"NetworkChannel_ConnectionChanged"


class NetworkChannel;
class NetworkManager;
class BusManager;
template <class T> class DataFieldCollector;

class INetworkChannelListener {
	public:
		virtual void channel_Connected( NetworkChannel* channel, const WoshHost& remote_host ) = 0;
		virtual void channel_Disconnected( NetworkChannel* channel, const std::string& host_name ) = 0;
		virtual void channel_Error( NetworkChannel* channel, int error_id, std::string error_description ) = 0;

		virtual void channel_incomingMessage( NetworkChannel* channel, Message* message ) = 0;
	public:
		virtual ~INetworkChannelListener() { }

};


class NetworkChannel :	public Object,
						public virtual IPropertiesProviderListener,
						public virtual IBusListener,
						public MethodRunner
 {
	WOSH_CLASSNAME(wosh::NetworkChannel)
	WOSH_CLASS_ABSTRACT(true)


	public:
		/**
		 * @brief  Empty constructor.
		 * @param name [in] optional name of the channel
		 */
		NetworkChannel( const std::string& name = "" );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~NetworkChannel();

	public:
		virtual WRESULT connect( unsigned long timeout = LIMIT_ULONG_MAX ) = 0;
		virtual WRESULT disconnect( unsigned long timeout = LIMIT_ULONG_MAX ) = 0;

		virtual WRESULT sendMessage( const Message* message ) = 0;
//		virtual WRESULT sendData( const char* data, unsigned long size ) = 0;

		virtual WRESULT ping( unsigned long timeout = 15000 ) = 0;

		virtual WRESULT declarateWoshHost() = 0;

/** @name Getters
 * @{
 ******************************************************************************/
	public:
		virtual bool isConnected() const = 0;

		/**
		 * @brief  
		 * @return 
		 */
		virtual std::string getProtocol() const = 0;

		virtual const std::string& getRemoteWoshName() const = 0;

		inline long getID() const								{ return this->id; }

		inline int getPriority() const							{ return this->priority; }

		virtual inline bool getDeleteFlag() const				{ return this->flagDelete; }

		inline const PropertiesProvider& getProperties() const	{ return Properties; }
		inline PropertiesProvider& getProperties()				{ return Properties; }

		inline const MethodsProvider& getMethods() const		{ return this->Methods; }
		inline MethodsProvider& getMethods()					{ return this->Methods; }

		inline const MessageQueue& getQueueOutgoing() const		{ return this->msgQueueOutgoing; }
		inline MessageQueue& getQueueOutgoing()					{ return this->msgQueueOutgoing; }

		static DataFieldCollector<NetworkChannel>* getDataFields();

//@}
/** @name Setters
 * @{
 ******************************************************************************/
	public:
		virtual WRESULT setListener( INetworkChannelListener* listener );

//@}
/** @name Message Events (incoming message)
 * @{
 ******************************************************************************/
	public:
		virtual void busMessage( const Message& message, const Bus* source );
//@}
/** @name IPropertiesProviderListener interface
 * @{
 ******************************************************************************/
 	public:
		virtual bool readingProperty( Property* property_curr, const PropertiesProvider* source );
		virtual bool updatingProperty( bool& do_update, const Variant& value_proposed, Property& property_current, const PropertiesProvider* source );
//@}
/** @name Internal methods
 * @{
 ******************************************************************************/
	protected:
		void setID( long id );

		WRESULT openDumpOutputToFile( const std::string& filename );
		WRESULT openDumpInputToFile( const std::string& filename );

		void setSeenNow();
		void setTransmittedNow( bool tx_succeeded );
		void setReceivedNow( bool rx_succeeded );

		inline void setDeleteFlag( bool value )		{ this->flagDelete = value; }

		friend class NetworkManager;

	private:
		Response* mmDoConnect( const Request* request );
		Response* mmDoDisconnect( const Request* request );
		Response* mmDoPing( const Request* request );

//@}
	protected:
		long id;								///< unique ID of che channel
		int priority;							///< priority [0;100]
		bool flagDelete;

		mutable PropertiesProvider Properties;	///< my configuration
		mutable MethodsProvider Methods;		///< my methods
		mutable LogContext Log;					///< my logger

		INetworkChannelListener* listener;		///< my listener

	protected:
		MessageQueue msgQueueOutgoing;

	protected: //stats & debug
		MutexRW statsMux;

		long lastSeen;
		long messageSentTs;
		int64 messageSentCount;
		int64 messageSentErrorCount;

		long messageReceivedTs;
		int64 messageReceivedCount;
		int64 messageReceivedErrorCount;

		FILE* dumpOutput;
		FILE* dumpInput;

}; // class def






/**
 * @class   wosh::NetworkChannel_ListChanged
 * @brief   Raised when 
 *
 * Internally, data is stored as wosh::Variant (STRING).
 *
 * Fields are:
 *  - \c 
 *

 * \code
 * \endcode
 *
 * @see     wosh::Fact
 * @see     wosh::WoshHost
 ****************************************************************************
 * @version 0.8.399 $Id: NetworkChannel.h 2836 2010-08-03 01:35:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
class NetworkChannel_ListChanged : public Fact_ListChanged
 {
	WOSH_SERIALIZABLE(wosh::NetworkChannel_ListChanged)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		NetworkChannel_ListChanged()
			: Fact_ListChanged( _NetworkChannel_EVENT_ListChanged ) { }
		/**
		 * @brief  Constructor with initializers.
		 * @param channel_name [in] added, updated or removed item 
		 * @param list_event [in] raised event within list/item
		 */
		explicit NetworkChannel_ListChanged( const std::string& channel_name, FACT_LIST_EVENT list_event )
			: Fact_ListChanged(channel_name, list_event, _WoshHost_EVENT_ListChanged) { }
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		NetworkChannel_ListChanged( const NetworkChannel_ListChanged& m )
			: Fact_ListChanged(m) { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~NetworkChannel_ListChanged() { }

	public:
		std::string getNetworkChannelName() const;

}; // class def



/**
 * @class   wosh::NetworkChannel_ConnectionChanged
 * @brief   Raised when 
 *
 * Internally, data is stored as wosh::Variant (STRING).
 *
 * Fields are:
 *  - \c 
 *

 * \code
 * \endcode
 *
 * @see     wosh::Fact
 * @see     wosh::NetworkChannel
 ****************************************************************************
 * @version 0.8.399 $Id: NetworkChannel.h 2836 2010-08-03 01:35:26Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
class NetworkChannel_ConnectionChanged : public Fact
 {
	WOSH_SERIALIZABLE(wosh::NetworkChannel_ConnectionChanged)

	public:
		/**
		 * @brief  Empty constructor.
		 */
		NetworkChannel_ConnectionChanged()
			: Fact( _NetworkChannel_EVENT_ConnectionChanged ) { }
		/**
		 * @brief  Constructor with initializers.
		 * @param woshname [in] the subject (host) of the event
		 */
		NetworkChannel_ConnectionChanged( const std::string& network_channel_name, int connection_state );
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		NetworkChannel_ConnectionChanged( const NetworkChannel_ConnectionChanged& m )
			: Fact(m) { }
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~NetworkChannel_ConnectionChanged() { }

	public:
		std::string getNetworkChannelName() const;
		int getConnectionState() const;


}; // class def



}; // namespace wosh

#endif //__WOSH_Core_NetworkChannel_H__
